/** 
 * @file:     gpt_framebuffer.c
 * @Author:   ChenBlue
 * @email:    ChenBlue952@qq.com
 * @data:     Mon Mar 13 11:52:26 2023
 * @brief:   
 */

#include <stdio.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>

#define DRIVER_NAME "my_fb"

struct fb_info *my_fb_info; // framebuffer信息

static int my_fb_open(struct fb_info *info, int user) {
    return 0;
}

static int my_fb_release(struct fb_info *info, int user) {
    return 0;
}

static struct fb_ops my_fb_ops = {
    .owner = THIS_MODULE,
    .fb_open = my_fb_open,
    .fb_release = my_fb_release,
};

static int __init my_fb_init(void) {
    // 分配fb_info结构体
    my_fb_info = framebuffer_alloc(0, NULL);
    if (!my_fb_info) {
        printk(KERN_ERR "Failed to allocate framebuffer\n");
        return -ENOMEM;
    }
    // 设置framebuffer信息
    my_fb_info->var = (struct fb_var_screeninfo) {
        .xres = 640,
        .yres = 480,
        .bits_per_pixel = 32,
        .red = { 16, 8, 0 },
        .green = { 24, 16, 8 },
        .blue = { 0, 8, 16 },
    };
    my_fb_info->fix = (struct fb_fix_screeninfo) {
        .id = DRIVER_NAME,
        .smem_start = (unsigned long)vmalloc(my_fb_info->var.yres_virtual * my_fb_info->fix.line_length),
        .smem_len = my_fb_info->var.yres_virtual * my_fb_info->fix.line_length,
        .type = FB_TYPE_PACKED_PIXELS,
        .visual = FB_VISUAL_TRUECOLOR,
        .line_length = my_fb_info->var.xres * my_fb_info->var.bits_per_pixel / 8,
    };
    // 设置framebuffer操作
    my_fb_info->fbops = &my_fb_ops;
    // 注册framebuffer
    if (register_framebuffer(my_fb_info) < 0) {
        printk(KERN_ERR "Failed to register framebuffer\n");
        framebuffer_release(my_fb_info);
        return -EINVAL;
    }
    printk(KERN_INFO "Framebuffer registered successfully\n");
    return 0;
}

static void __exit my_fb_exit(void) {
    // 注销framebuffer
    unregister_framebuffer(my_fb_info);
    // 释放分配的资源
    vfree((void*)my_fb_info->fix.smem_start);
    framebuffer_release(my_fb_info);
}

module_init(my_fb_init);
module_exit(my_fb_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple framebuffer driver");

